package com.itheima.domain.impl;

import com.itheima.domain.Observer;
import com.itheima.domain.Subject;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: MyTopic
 * @Description: 被观察者对象
 * 注册与注销观察者方法的实现非常简单，额外的方法postMessage()将被客户端应用来提交一个字符串消息给此主题。
 * 注意，布尔变量用于追踪主题状态的变化并且通知观察者此种变化。这个变量是必须的，因为如果没有更新，
 * 但是有人调用notifyObservers()方法，他就不能发送错误的通知信息给观察者。
 * @author: Yrd
 * @date: 2021-11-02 14:47
 */
public class MyTopic implements Subject {

    public List<Observer> observers;
    private String message;
    private boolean changed;
    private final Object MUTEX = new Object();

    public MyTopic() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void register(Observer observer) {
        if (observer == null){
            throw new NullPointerException("Null Observer");
        }
        if (!observers.contains(observer)){
            observers.add(observer);
        }
    }

    @Override
    public void unregister(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        List<Observer> observerList = null;
        //synchronization is used to make sure any observer registered after message is received is not notified
        //同步用于确保在收到消息后注册的任何观察者都不会收到通知
        synchronized (MUTEX){
            System.out.println("线程名称："+Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (!changed)
                return;
            observerList = new ArrayList<>(this.observers);
            this.changed = false;
        }
        for (Observer observer : observerList) {
            observer.update();
        }

    }

    @Override
    public Object getUpdate(Observer observer) {
        return this.message;
    }

    //method to post message to the topic
    public void postMessage(String message){
        System.out.println("Message Posted to Topic:"+message);
        this.message = message;
        this.changed = true;
        notifyObservers();
    }
}
